package com.coc.myquartz.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.UnableToInterruptJobException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 配置集群quartz不能實現其他接口
 * @author joke
 *
 */
public abstract class ConcurrentJobManage implements JobManage/*,SpringContextJob */{

    private static Map<String, Lock> locks = new ConcurrentHashMap<String,Lock>();

    public ConcurrentJobManage(){
        synchronized (locks){
            if (!locks .containsKey(getClass().getName())) {
                locks.put(getClass().getName(),new Lock());
            }
        }
    }

    @Override
    public void interrupt() throws UnableToInterruptJobException {
        // do nothing
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        try{
            if (!tryLock()){
                return;
            }
            doExecute();
        }finally {
            tryUnLock();  // 必须在finally中关闭
        }
    }


    /**
     *  正真执行任务的方法
     */
    protected abstract void doExecute();


    @Override
    public void startjob() {
        // do nothing
    }

    protected boolean tryLock() {
        Lock lock = locks.get(getClass().getName());
        if (lock.running) {
            return false;
        } else {
            synchronized (lock) {
                if (lock.running) {
                    return false;
                } else {
                    lock.running = true;
                    lock.ownerThread = Thread.currentThread();
                    return true;
                }
            }
        }
    }

    protected void tryUnLock() {
        Lock lock = locks.get(getClass().getName());
        if (lock.ownerThread == Thread.currentThread() ) {
            lock.running = false;
        }

    }

    /**
     * Lock 锁
     */
    class Lock{
        public Thread ownerThread;
        boolean running;
        Object lock;

        Lock(){
            running = false;
            lock = new Object();
        }
    }


}
